/*********************************************************************************
 *      Copyright:  (C) 2022 Li Yanting<liyanting2@163.com>
 *                  All rights reserved.
 *
 *       Filename:  main.c
 *    Description:  This file 
 *                 
 *        Version:  1.0.0(04/20/2022)
 *         Author:  Li Yanting <liyanting2@163.com>
 *      ChangeLog:  1, Release initial version on "04/20/2022 04:47:46 PM"
 *                 
 ********************************************************************************/

#include "main.h"

int main(int argc, char **argv)
{
	int                  sockfd;
	int                  serv_port;
	int                  clifd;

	int                  i;
	char                 opt;
	int                  daemon_run = 0;
	char                 buffer[128];

	int                  epollfd;
	struct epoll_event   event;
	struct epoll_event   event_array[MAX_EVENT];
	int                  events;
	
	sqlite3             *sql_db;

	int                  rv;

	char                *s= "|";
	char                *token = NULL;
	char                 HOST_NUMBER[32];
	char                 format_time[64];
	char                 temper[32];

	struct option        opt_long[] = 
	{
		{"serv_port", required_argument, NULL, 'p'},
		{"daemon", no_argument, NULL, 'b'},
		{"help", no_argument, NULL, 'h'},
		{NULL, 0, NULL, 0}
	};

	if( (opt = getopt_long(argc, argv, "p:bh", opt_long, NULL)) != -1 )
	{
		dbg_printf("opt: %c\n", opt);

		switch(opt)
		{
			case 'p':
				serv_port = atoi(optarg);
				break;
			case 'b':
				daemon_run = 1;
				break;
			case 'h':
				print_usage(argv[0]);
				break;
			default:
				break;
		}
	}

	if(!serv_port)
	{
		print_usage(argv[0]);
		return -1;
	}

	rv = logger_init("running.log", LOG_LEVEL_DEBUG);
	if( rv < 0)
    {
        fprintf(stderr, "initial logger system failure\n");
        return -2;
    }

	if( daemon_run )
	{
		daemon(0, 0);
	}

	signal(SIGINT, program_stop);
	signal(SIGTERM, program_stop);

	create_database(&sql_db);

	if((sockfd = socket_server_init(serv_port)) < 0 )
	{
		log_error("socket init failure: %s\n", strerror(errno));
		return -2;
	}

	if( (epollfd = epoll_create(MAX_EVENT)) < 0 )
	{
		dbg_printf("create epollfd failure\n");
		log_error("create epollfd failure\n");
		return -3;
	}
	dbg_printf("create epollfd successful\n");
	log_info("create epollfd successful\n");

	event.events = EPOLLIN;
	event.data.fd = sockfd;
	if( epoll_ctl(epollfd, EPOLL_CTL_ADD, sockfd, &event) < 0 )
	{
		dbg_printf("add sockfd to event failure\n");
		log_error("add sockfd to event failure\n");

		return -4;
	}
	dbg_printf("add sockfd to event successful\n");
	log_info("add sockfd to event successful\n");

	while( !g_program_stop )
	{
		dbg_printf("start to listen event\n");
		events = epoll_wait(epollfd, event_array, MAX_EVENT, -1);
		if(events < 0)
		{
			dbg_printf("epoll_wait failure\n");
			break;
		}
		else if(0 == events)
		{
			dbg_printf("epoll_wait timeout\n");
			continue;
		}
		
		for(i = 0; i < events; i++)
		{
			if( (event_array[i].events&EPOLLERR) || (event_array[i].events&EPOLLHUP) )
			{
				dbg_printf("epoll_wait fd failure\n");
				epoll_ctl(epollfd, EPOLL_CTL_DEL, event_array[i].data.fd, NULL);
				close(event_array[i].data.fd);
			}

			if(event_array[i].data.fd == sockfd)
			{
				dbg_printf("got sockfd action\n");
				if( (clifd = accept(sockfd, (struct sockaddr *)NULL, NULL)) < 0 )
				{
					dbg_printf("accept clifd failure: %s\n", strerror(errno));
					continue;
				}
				dbg_printf("accept clifd successfully\n");

				event.data.fd = clifd;
				event.events = EPOLLIN;
				if( epoll_ctl(epollfd, EPOLL_CTL_ADD, clifd, &event) < 0 )
				{
					dbg_printf("add clifd to event failure: %s\n", strerror(errno));
					close(event_array[i].data.fd);
					continue;
				}
				dbg_printf("add clifd to event successfully\n");
			}
			else
			{
				dbg_printf("got clifd action\n");
				memset(&buffer, 0, sizeof(buffer));
				if( read(event_array[i].data.fd, buffer, sizeof(buffer)) <= 0 )
				{
					dbg_printf("client got disconnect or read data from clifd failure\n");
					epoll_ctl(epollfd, EPOLL_CTL_DEL, event_array[i].data.fd, NULL);
					close(event_array[i].data.fd);
					continue;
				}
				dbg_printf("buffer: %s\n", buffer);

				dbg_printf("start to parser the data\n");
				token = strtok(buffer, s);
				strcpy(HOST_NUMBER, token);
				dbg_printf("%s\n", HOST_NUMBER);
				token = strtok(NULL, s);
				strcpy(format_time, token);
				dbg_printf("%s\n", format_time);
				token = strtok(NULL, s);
				strcpy(temper, token);
				dbg_printf("%s\n", temper);

				dbg_printf("got data[%s %s %s]\n", HOST_NUMBER, format_time, temper);

				create_statement(sql_db, HOST_NUMBER);
			
				if( sql_insert(sql_db, HOST_NUMBER, format_time, temper) < 0 )
				{
					dbg_printf("insert data to %s failure\n", HOST_NUMBER);
				}
			}
		}
	}
	close(sockfd);
}

static inline void print_usage(char *progname)
{
	printf("%s usage:\n", progname);
	printf("-p(--port): specify a port to listen.\n");
	printf("-b(--daemon): set program running in the backgrund.\n");
	printf("-h(--help): print this help information.\n");
	printf("example: %s -p 12345 -b\n", progname);
}

void program_stop(int signum)
{
	g_program_stop = 1;
}
